package com.yq.processor.processor;

import com.google.auto.service.AutoService;
import com.yq.processor.annotation.TestAnnotation;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;

/**
 * @author yangqing
 * @time 2023/4/10 14:02
 * @describe 目标： 不做代码生成，仅仅查看相关api
 * 1. 注解处理器什么时候被调用：
 * 2. process方法调用次数（是每次扫描到支持的注解后就回调吗）
 * 3. process能获取什么信息，返回值代表什么：
 */
@AutoService(Processor.class)
public class TestAnnotationProcessor extends AbstractProcessor {
    /**
     * 设置支持的源版本，默认为RELEASE_6
     * 两种方式设置版本：
     * 1. 此处返回指定版本
     * 2. 类上面设置SupportedSourceVersion注解，并传入版本号
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    /**
     * 设置支持的注解类型，默认为空集合（都不支持）
     * 两种方式设置注解集合：
     * 1. 此处返回支持的注解集合
     * 2. 类上面设置SupportedAnnotationTypes注解，并传入需要支持的注解
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new HashSet<>();
        types.add(TestAnnotation.class.getCanonicalName());
        return types;
    }

    /**
     * 初始化操作
     *
     * @param processingEnv 环境
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }


    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "TestAnnotationProcessor working >>>>>> ==================begin=======================");
        for (TypeElement annotation : annotations) {
            Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);
            for (Element element : elements) {

                TypeMirror typeMirror = element.asType();//返回元素定义的类型
                println(typeMirror.toString());

                Name simpleName = element.getSimpleName();//返回此元素的简单名称,比如activity名
                println(simpleName);

                ElementKind kind = element.getKind();// 元素种类： 是类，还是方法，还是...
                println(kind.toString());

                Set<Modifier> modifiers = element.getModifiers();//修饰符 private public protected ...
                for (Modifier modifier : modifiers) {
                    println(modifier.toString());
                }

                Element enclosingElement = element.getEnclosingElement();//返回包含此元素的最里面的元素
                println(enclosingElement.getSimpleName());

                TestAnnotation testAnnotation = element.getAnnotation(TestAnnotation.class);//返回此元素针对指定类型的注解
                println(testAnnotation.value());

                // element 有多个子类，必要时，我们需要将element转成子类，比如TypeElement VariableElement ExecutableElement
                //TypeElement定义的一个类或接口程序元素，相当于当前注解所在的class对象
                if (element instanceof TypeElement) {
                    TypeElement typeElement = (TypeElement) element;
                    NestingKind nestingKind = typeElement.getNestingKind();//返回此类型元素的嵌套种类
                    println("nestingKind:  " + nestingKind.toString());

                    TypeMirror superclass = typeElement.getSuperclass();//返回此类型元素的直接超类
                    println("getSuperclass:  " + superclass.toString());

                    List<? extends TypeMirror> interfaces = typeElement.getInterfaces();//返回直接由此类实现或直接由此接口扩展的接口类型
                    for (TypeMirror anInterface : interfaces) {
                        println("getInterfaces:  " + anInterface.toString());
                    }

                    List<? extends TypeParameterElement> typeParameters = typeElement.getTypeParameters();
                    for (TypeParameterElement typeParameter : typeParameters) {
                        println("getTypeParameters: " + typeParameter.getSimpleName());
                    }
                }

                //VariableElement 除了拥有Element的方法以外还有以下两个方法
                if (element instanceof VariableElement) {
                    VariableElement variableElement = (VariableElement) element;
                    Object constantValue = variableElement.getConstantValue();
                    println("constantValue:  " + constantValue);

                    Element enclosingElement1 = variableElement.getEnclosingElement();
                    println("enclosingElement1:  " + enclosingElement1);
                }
                println("");

            }

            Set<? extends Element> elementsAnnotatedWith = env.getElementsAnnotatedWith(TestAnnotation.class);
            for (Element element : elementsAnnotatedWith) {
                if (element instanceof ExecutableElement) {//ExecutableElement 表示类或接口中的方法元素
                    ExecutableElement executableElement = (ExecutableElement) element;
                    Element enclosingElement = executableElement.getEnclosingElement();//获取所在的类
                    Name simpleName = executableElement.getSimpleName();//获取当前方法名
                    println("current method: " + simpleName + "  which include in class:" + enclosingElement.getSimpleName());
                }
            }
        }
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "TestAnnotationProcessor working >>>>>> ==================end=======================\n\n");
        return true;
    }

    private void println(CharSequence msg) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "TestAnnotationProcessor working >>>>>> " + msg);
    }
}
